import { Injectable } from '@nestjs/common';
import dayjs from 'dayjs';
import utc from 'dayjs/plugin/utc';
import timezone from 'dayjs/plugin/timezone';
import relativeTime from 'dayjs/plugin/relativeTime';
import customParseFormat from 'dayjs/plugin/customParseFormat';
import duration from 'dayjs/plugin/duration';
import isBetween from 'dayjs/plugin/isBetween';
import isSameOrAfter from 'dayjs/plugin/isSameOrAfter';
import isSameOrBefore from 'dayjs/plugin/isSameOrBefore';
import quarterOfYear from 'dayjs/plugin/quarterOfYear';
import dayOfYear from 'dayjs/plugin/dayOfYear';
import weekOfYear from 'dayjs/plugin/weekOfYear';
import isoWeek from 'dayjs/plugin/isoWeek';

/**
 * Day.js 日期处理服务
 * 基于 NestJS 官方示例实现
 * 参考: https://docs.nestjs.cn/fundamentals/dependency-injection
 * 对应 Java: DateUtils
 */
@Injectable()
export class DayjsService {
  constructor() {
    // 初始化插件
    dayjs.extend(utc);
    dayjs.extend(timezone);
    dayjs.extend(relativeTime);
    dayjs.extend(customParseFormat);
    dayjs.extend(duration);
    dayjs.extend(isBetween);
    dayjs.extend(isSameOrAfter);
    dayjs.extend(isSameOrBefore);
    dayjs.extend(quarterOfYear);
    dayjs.extend(dayOfYear);
    dayjs.extend(weekOfYear);
    dayjs.extend(isoWeek);
  }

  /**
   * 获取 dayjs 实例
   */
  getDayjs() {
    return dayjs;
  }

  /**
   * 格式化日期
   */
  format(
    date: Date | string | number,
    format: string = 'YYYY-MM-DD HH:mm:ss',
  ): string {
    return dayjs(date).format(format);
  }

  /**
   * 解析日期字符串
   */
  parse(dateStr: string, format?: string): dayjs.Dayjs | null {
    if (!dateStr) return null;

    try {
      const parsed = format ? dayjs(dateStr, format) : dayjs(dateStr);
      return parsed.isValid() ? parsed : null;
    } catch {
      return null;
    }
  }

  /**
   * 获取当前时间
   */
  now(): dayjs.Dayjs {
    return dayjs();
  }

  /**
   * 获取当前时间戳
   */
  timestamp(): number {
    return dayjs().valueOf();
  }

  /**
   * 时间戳转日期
   */
  fromTimestamp(timestamp: number): dayjs.Dayjs {
    return dayjs(timestamp);
  }

  /**
   * 日期转时间戳
   */
  toTimestamp(date: Date | string | number): number {
    return dayjs(date).valueOf();
  }

  /**
   * 添加时间
   */
  add(
    date: Date | string | number,
    amount: number,
    unit: dayjs.ManipulateType,
  ): dayjs.Dayjs {
    return dayjs(date).add(amount, unit);
  }

  /**
   * 减去时间
   */
  subtract(
    date: Date | string | number,
    amount: number,
    unit: dayjs.ManipulateType,
  ): dayjs.Dayjs {
    return dayjs(date).subtract(amount, unit);
  }

  /**
   * 计算时间差
   */
  diff(
    date1: Date | string | number,
    date2: Date | string | number,
    unit: dayjs.QUnitType = 'millisecond',
  ): number {
    return dayjs(date1).diff(dayjs(date2), unit);
  }

  /**
   * 获取开始时间
   */
  startOf(date: Date | string | number, unit: dayjs.OpUnitType): dayjs.Dayjs {
    return dayjs(date).startOf(unit);
  }

  /**
   * 获取结束时间
   */
  endOf(date: Date | string | number, unit: dayjs.OpUnitType): dayjs.Dayjs {
    return dayjs(date).endOf(unit);
  }

  /**
   * 判断是否为今天
   */
  isToday(date: Date | string | number): boolean {
    return dayjs(date).isSame(dayjs(), 'day');
  }

  /**
   * 判断是否为昨天
   */
  isYesterday(date: Date | string | number): boolean {
    return dayjs(date).isSame(dayjs().subtract(1, 'day'), 'day');
  }

  /**
   * 判断是否为明天
   */
  isTomorrow(date: Date | string | number): boolean {
    return dayjs(date).isSame(dayjs().add(1, 'day'), 'day');
  }

  /**
   * 判断是否为同一天
   */
  isSameDay(
    date1: Date | string | number,
    date2: Date | string | number,
  ): boolean {
    return dayjs(date1).isSame(dayjs(date2), 'day');
  }

  /**
   * 判断是否在范围内
   */
  isBetween(
    date: Date | string | number,
    start: Date | string | number,
    end: Date | string | number,
    unit?: dayjs.OpUnitType,
  ): boolean {
    return dayjs(date).isBetween(dayjs(start), dayjs(end), unit);
  }

  /**
   * 获取相对时间描述
   */
  fromNow(date: Date | string | number): string {
    return dayjs(date).fromNow();
  }

  /**
   * 获取相对时间描述（中文）
   */
  fromNowZh(date: Date | string | number): string {
    const now = dayjs();
    const target = dayjs(date);
    const diffMs = now.diff(target);
    const diffSeconds = Math.floor(diffMs / 1000);
    const diffMinutes = Math.floor(diffSeconds / 60);
    const diffHours = Math.floor(diffMinutes / 60);
    const diffDays = Math.floor(diffHours / 24);

    if (diffSeconds < 60) {
      return '刚刚';
    } else if (diffMinutes < 60) {
      return `${diffMinutes}分钟前`;
    } else if (diffHours < 24) {
      return `${diffHours}小时前`;
    } else if (diffDays < 7) {
      return `${diffDays}天前`;
    } else {
      return target.format('YYYY-MM-DD');
    }
  }

  /**
   * 设置时区
   */
  setTimezone(date: Date | string | number, timezone: string): dayjs.Dayjs {
    return dayjs(date).tz(timezone);
  }

  /**
   * 转换为 UTC
   */
  toUTC(date: Date | string | number): dayjs.Dayjs {
    return dayjs(date).utc();
  }

  /**
   * 转换为本地时间
   */
  toLocal(date: Date | string | number): dayjs.Dayjs {
    return dayjs(date).local();
  }

  /**
   * 获取持续时间
   */
  duration(amount: number, unit: any): any {
    return dayjs.duration(amount, unit);
  }

  /**
   * 判断日期是否有效
   */
  isValid(date: any): boolean {
    return dayjs(date).isValid();
  }

  /**
   * 获取月份天数
   */
  daysInMonth(date: Date | string | number): number {
    return dayjs(date).daysInMonth();
  }

  /**
   * 获取年份
   */
  year(date: Date | string | number): number {
    return dayjs(date).year();
  }

  /**
   * 获取月份（0-11）
   */
  month(date: Date | string | number): number {
    return dayjs(date).month();
  }

  /**
   * 获取日期
   */
  date(date: Date | string | number): number {
    return dayjs(date).date();
  }

  /**
   * 获取小时
   */
  hour(date: Date | string | number): number {
    return dayjs(date).hour();
  }

  /**
   * 获取分钟
   */
  minute(date: Date | string | number): number {
    return dayjs(date).minute();
  }

  /**
   * 获取秒
   */
  second(date: Date | string | number): number {
    return dayjs(date).second();
  }

  /**
   * 获取毫秒
   */
  millisecond(date: Date | string | number): number {
    return dayjs(date).millisecond();
  }

  /**
   * 获取星期几
   */
  day(date: Date | string | number): number {
    return dayjs(date).day();
  }

  /**
   * 获取季度
   */
  quarter(date: Date | string | number): number {
    return dayjs(date).quarter();
  }

  /**
   * 获取年份中的第几天
   */
  dayOfYear(date: Date | string | number): number {
    return dayjs(date).dayOfYear();
  }

  /**
   * 获取年份中的第几周
   */
  week(date: Date | string | number): number {
    return dayjs(date).week();
  }

  /**
   * 获取年份中的第几周（ISO）
   */
  isoWeek(date: Date | string | number): number {
    return dayjs(date).isoWeek();
  }
}
